unit XmlWrap;

interface
uses xmldom, XMLIntf, msxmldom, XMLDoc;

type TXmlWrap = class
  private
  public
    FXml: IXMLDocument;
    FSel: IDomNodeSelect;
    constructor Create;
    destructor Destroy;override;
    procedure Load(AXML: String);
    function LoadFile(AFileName: String): Boolean;
    function Get(APath: String): String;
    function Count(APath: String): Integer;
    function Geti(APath: String;AIndex: Integer): String;

    procedure ConvertVarToDefaultValue(ANode: IXMLNode);
    procedure Replace(ADest,ASource: IXMLNode);

    //clone child nodes in AValue and copy it(them) to ANode
    procedure Assign(ADest,ASource: IXMLNode);
    procedure AssignByPath(ANode: IXMLNode;ADestPath,ASourcePath: String);
    procedure AssignTextByPath(ANode: IXMLNode;APath,AText: String);
    procedure AssignValueByPath(ANode: IXMLNode;APath:String;AValue: IXMLNode);

    function SelectNode(ANode: IXMLNode; APath: String): IXMLNode;
    function RootNode: IXMLNode;

    function IsVar(ANode: IXMLNode): Boolean;
    procedure ConvertAllValueToDefault(ANode: IXMLNode);

    function PathOfNode(ARNode,ANode: IXMLNode): String;
    function PathOfVar(ANode,AVar: IXMLNode): String;
    function NameOfVar(AVar: IXMLNode): String;





end;


implementation

{ TXmlWrap }

procedure TXmlWrap.Assign(ADest, ASource: IXMLNode);
var Source1: IXMLNode;
    Child1: IXMLNode;
    i: Integer;
begin
  ADest.ChildNodes.Clear;
  for i := 0 to ASource.ChildNodes.Count-1 do begin
    Child1:=ASource.ChildNodes.Get(i).CloneNode(True);
    ADest.ChildNodes.Add(Child1);
  end;
end;

procedure TXmlWrap.AssignByPath(ANode: IXMLNode; ADestPath, ASourcePath: String);
var DestNode1,SourceNode1:IXMLNode;
begin
  DestNode1:=Self.SelectNode(ANode,ADestPath);
  SourceNode1:=SelectNode(ANode,ASourcePath);
  Assign(DestNode1,SourceNode1);
end;

procedure TXmlWrap.AssignTextByPath(ANode: IXMLNode;APath, AText: String);
var Node1: IXMLNode;
begin
  Node1:=SelectNode(ANode,APath);
  Node1.ChildNodes.Clear;
  Node1.Text:=AText;
end;

procedure TXmlWrap.AssignValueByPath(ANode: IXMLNode; APath: String;
  AValue: IXMLNode);
var Node1: IXMLNode;
begin
  Node1:=SelectNode(ANode,APath);
  Assign(Node1,AValue);
end;

procedure TXmlWrap.ConvertAllValueToDefault(ANode: IXMLNode);
var Node1: IXMLNode;
    i: Integer;
begin
  if ANode.ChildNodes.Count=1 then begin
    Node1:=ANode.ChildNodes.Get(0);
    if IsVar(ANode) then begin
      Assign(ANode,SelectNode(ANode,'var/default'));
    end else begin
      ConvertAllValueToDefault(Node1);
    end;
  end else if ANode.ChildNodes.Count>1 then begin
    for i := 0 to ANode.ChildNodes.Count-1 do begin
      ConvertAllValueToDefault(ANode.ChildNodes.Get(i));
    end;
  end;
end;

procedure TXmlWrap.ConvertVarToDefaultValue(ANode: IXMLNode);
var D1: String;
begin
  D1:=ANode.ChildNodes.FindNode('var').ChildNodes.FindNode('default').Text;
  ANode.ChildNodes.Clear;
  ANode.NodeValue:=D1;
end;

function TXmlWrap.Count(APath: String): Integer;
begin
  Result:=FSel.selectNodes(APath).length;
end;

constructor TXmlWrap.Create;
begin
  FXml:=TXMLDocument.Create(nil);
end;

destructor TXmlWrap.Destroy;
begin
  inherited;
end;

function TXmlWrap.Get(APath: String): String;
var Node1: IDOMNode;
begin
  Node1:=FSel.selectNode(APath);
  if Node1=nil then begin
    Result:='$none';
  end else begin
    Result:=Node1.firstChild.nodeValue;
  end;
end;

function TXmlWrap.Geti(APath: String; AIndex: Integer): String;
begin
  Result:=FSel.selectNodes(APath).item[AIndex].firstChild.nodeValue;
end;

function TXmlWrap.IsVar(ANode: IXMLNode): Boolean;
begin
  if ANode.ChildNodes.FindNode('var') = nil then begin
    Result:=False;
  end else begin
    Result:=True;
  end;
end;

procedure TXmlWrap.Load(AXML: String);
begin
  FXml.LoadFromXML(AXML);
  FXml.Active:=True;
  FSel:=FXml.DOMDocument as IDomNodeSelect;
end;

function TXmlWrap.LoadFile(AFileName: String): Boolean;
begin
  FXml.LoadFromFile(AFileName);
  FXml.Active:=True;
  FSel:=FXml.DOMDocument as IDomNodeSelect;
  Result:=True;
end;


function TXmlWrap.NameOfVar(AVar: IXMLNode): String;
begin
  Result:=AVar.ChildNodes.FindNode('name').Text;
end;

function TXmlWrap.PathOfNode(ARNode, ANode: IXMLNode): String;
var Node1: IXMLNode;
    Path1: String;
begin
  if ANode=ARNode then begin
    Result:=ANode.NodeName;
  end else begin
    Node1:=ANode.ParentNode;
    Path1:=PathOfNode(ARNode,Node1);
    Result:=Path1+'/'+ANode.NodeName;
  end;
end;

function TXMLWrap.PathOfVar(ANode, AVar: IXMLNode): String;
var R1: String;
    Child1: IXMLNode;
    i: Integer;
begin
  //ShowMessage(ANode.XML);
  //ShowMessage(AVar.XML);
  if ANode.ChildNodes.Count=0 then begin
    Result:='';
  end else begin
    Result:='';
    for i := 0 to ANode.ChildNodes.Count-1 do begin
      Child1:=ANode.ChildNodes.Get(i);
      if IsVar(Child1) then begin
        if NameOfVar(Child1.ChildNodes.Get(0)) =AVar.NodeName then begin
          Result:=Child1.NodeName;
        end;
      end else begin
        R1:=PathOfVar(Child1,AVar);
        if R1<>'' then begin
          Result:=Child1.NodeName+'/'+R1;
        end;
      end;
    end;
  end;
end;

procedure TXmlWrap.Replace(ADest, ASource: IXMLNode);
begin
  ADest.ChildNodes.ReplaceNode(ADest,ASource);
end;

function TXmlWrap.RootNode: IXMLNode;
begin
  Result:=FXml.ChildNodes.Get(0);
end;

function TXmlWrap.SelectNode(ANode: IXMLNode;APath: String): IXMLNode;
var Node1: IXMLNode;
    NodeName1: String;
    Path1: String;
    i: Integer;
begin
  i:=Pos('/',APath);
  if i=0 then begin
    NodeName1:=APath;
    Result:=ANode.ChildNodes.FindNode(NodeName1);
  end else begin
    NodeName1:=Copy(APath,0,i-1);
    Path1:=Copy(APath,i+1,Length(APath));
    Node1:=ANode.ChildNodes.FindNode(NodeName1);
    Result:=SelectNode(Node1,Path1);
  end;
end;

end.
